//#include <windows.h>		// Header File For Windows
//#include <d3d9.h>           // Header File For D3D9
//#include <d3dx9.h>          // Header File For D3D9 Helper

#include "EngineHeader.h"

using namespace LSH;

int width = 1024;
int height = 768;

HWND		hWnd = NULL;		// Holds Our Window Handle

//IDirect3D9*             g_pD3D = NULL;              // D3D9 InterFace
//IDirect3DDevice9*       g_pd3dDevice = NULL;        // D3D9 Devices InterFace
//IDirect3DVertexBuffer9* g_pVB = NULL;               // D3D9 Vertex Buffer

//IDirect3D9*             g_pD3D = NULL;              // D3D9 InterFace
//IDirect3DDevice9*       g_pd3dDevice = NULL;        // D3D9 Devices InterFace
VertexBuffer* g_pVB = NULL;               // D3D9 Vertex Buffer
IndexBuffer* g_pIB = NULL;

Timer g_timer;

struct CUSTOMVERTEX
{
    FLOAT x, y, z;      // Position
    DWORD color;        // The vertex color.
};

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)

void DestroyScene();

BOOL InitScene(){
    CUSTOMVERTEX vertices[] =
    {
        { -25.0f, -25.0f, 40.0f, 0xffff0000, }, // x, y, z, color
        {   0.0f,  25.0f, 40.0f, 0xff00ff00, },
        {  25.0f, -25.0f, 40.0f, 0xff00ffff, },
    };

    g_pVB = CM_NEW(VertexBuffer); 

    g_pVB->create(sizeof(CUSTOMVERTEX), 3, D3DFVF_CUSTOMVERTEX);

    g_pVB->map(vertices, sizeof(vertices));

    
    DWORD indexs[] = {0, 1, 2};

    g_pIB = CM_NEW(IndexBuffer);

    g_pIB->create(ARRAYSIZE(indexs));

    g_pIB->map(indexs, sizeof(indexs));

    //Set matrix for world , view , projection 
    D3DXMATRIX matWorld;
    D3DXMatrixIdentity(&matWorld);
    Rander::GetSingleton().getD3DDevice()->SetTransform(D3DTS_WORLD, &matWorld);

    D3DXMATRIX matView;
    D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3(0, 0, -50), &D3DXVECTOR3(0, 0, 0), &D3DXVECTOR3(0, 1, 0));
    Rander::GetSingleton().getD3DDevice()->SetTransform(D3DTS_VIEW, &matView);

    D3DXMATRIX matProjection;
    D3DXMatrixPerspectiveFovLH(&matProjection, D3DX_PI/4.0f, 1.3333f, 0, 1000);
    if(FAILED(Rander::GetSingleton().getD3DDevice()->SetTransform(D3DTS_PROJECTION, &matProjection))){
        return FALSE;
    }
    
    D3DVIEWPORT9 viewPort;
    viewPort.X = viewPort.Y = 0;
    viewPort.Width = width;
    viewPort.Height = height;
    viewPort.MinZ = 0;
    viewPort.MaxZ = 1;
    Rander::GetSingleton().getD3DDevice()->SetViewport(&viewPort);

    Rander::GetSingleton().getD3DDevice()->SetRenderState(D3DRS_LIGHTING, FALSE);

    g_timer.start();

    String log = StringConvert::format(_T("InitScene success! start time=%f\n"), g_timer.getTime());
    Console::GetSingleton().print(EPL_DEBUG, log);

    return TRUE;
}

void DestroyScene(){
    return;
}

void DrawDirectx9Scene(){
    IDirect3DDevice9* pD3dDevice = Rander::GetSingleton().getD3DDevice();
    pD3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0);

    // Begin the scene
    pD3dDevice->BeginScene();

    // Rendering of scene objects happens here
    g_pVB->SetAsStreamSource();

    g_pIB->SetAsIndicesSource();

    pD3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 3, 0, 1);

    //pD3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

    // End the scene
    pD3dDevice->EndScene();

    pD3dDevice->Present( NULL, NULL, NULL, NULL );
}

void DestortyDirectX();

BOOL InitDirectX(int bits){
    Console::Create();
    Console::GetSingleton().show(String(_T("myConsole1")), 300, 200);
    Rander::Create();
    Rander::GetSingleton().create(hWnd, TRUE, width, height, bits);
    InitScene();
    return TRUE;
}

void DestortyDirectX(){
    Rander::GetSingleton().shutDown();
}


LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT ("DirectX Test");
    MSG          msg;
    WNDCLASSEX   wndclassex  = {0};
    wndclassex.cbSize        = sizeof(WNDCLASSEX);
    wndclassex.style         = CS_HREDRAW | CS_VREDRAW;
    wndclassex.lpfnWndProc   = WndProc;
    wndclassex.cbClsExtra    = 0;
    wndclassex.cbWndExtra    = 0;
    wndclassex.hInstance     = hInstance;
    wndclassex.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    wndclassex.hCursor       = LoadCursor (NULL, IDC_ARROW);
    wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
    wndclassex.lpszMenuName  = NULL;
    wndclassex.lpszClassName = szAppName;
    wndclassex.hIconSm       = wndclassex.hIcon;

    if (!RegisterClassEx (&wndclassex))
    {
        MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR);
        return 0;
    }

    hWnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW, 
        szAppName, 
        TEXT ("DirectX"),
        WS_OVERLAPPEDWINDOW,
        50, 
        50, 
        width, 
        height,
        NULL, 
        NULL, 
        hInstance,
        NULL);

    ShowWindow(hWnd, iCmdShow);
    UpdateWindow(hWnd);

    InitDirectX(32);

    ZeroMemory (&msg, sizeof(msg));
    while (msg.message != WM_QUIT)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
        else{
            DrawDirectx9Scene();
        }
    }

    return msg.wParam;
}


LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    //PAINTSTRUCT ps;
    switch (message)
    {
    case WM_CREATE:
        {
            // center the window
            RECT rect;
            GetWindowRect(hwnd, &rect);

            int nWndWidth = rect.right - rect.left;
            int nWndHeight = rect.bottom - rect.top;

            int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
            int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);

            rect.left = (nScreenWidth - nWndWidth) / 2;
            rect.top = (nScreenHeight - nWndHeight) / 2;

            SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, nWndWidth, nWndHeight, SWP_SHOWWINDOW);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_KEYDOWN:
        {
            switch (wParam)
            {
            case VK_UP:
                break;
            case VK_DOWN:

                break;
            case VK_LEFT:

                break;
            case VK_RIGHT:
                break;
            case VK_ESCAPE:
                PostQuitMessage(0);
                break;
            }
        }
        break;
    case WM_KEYUP:
        {
            switch(wParam)
            {
            case VK_SNAPSHOT:
                //theApp.saveScreen();
                break;
            }
        }
        break;
    case WM_SYSKEYDOWN:
        {

        }
        break;
    case WM_SYSKEYUP:
        {

        }
        break;
    case WM_MOUSEMOVE:
        {
            int x_pos = LOWORD(lParam);
            int y_pos = HIWORD(lParam);

            return 0;
        }
        break;
    case WM_LBUTTONDOWN:
        {

        }
        break;
    case WM_LBUTTONUP:
        {
            g_timer.reset();
            Console::GetSingleton().clear();
        }
        break;
    case WM_RBUTTONDOWN:
        {
            
        }
        break;
    case WM_RBUTTONUP:
        {
            static BOOL a = FALSE;
            a = !a;
            if(a){
                g_timer.stop();
            }else{
                g_timer.start();
                String log = StringConvert::format(_T("current time=%f\n"), g_timer.getTime());
                Console::GetSingleton().print(EPL_WARNING, log);
            }
        }
        break;
    case WM_MBUTTONDOWN:
        {

        }
        break;
    case WM_MBUTTONUP:
        {

        }
        break;
    case WM_MOUSEWHEEL:
        {
        }
        break;
    case WM_CHAR:
        break;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}